package modele;

import GestionThread.GestionThread;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author marc
 */
public class Environnement extends Observable implements Runnable {

    protected HashMap<Case, Position> HMCases;
    protected Case[][] tabCases;
    protected int hauteur, largeur;
    protected boolean pause;
    protected GestionThread gestionnaire;
    protected int iteration;
    protected int intervalle;

    public Environnement(int h, int l) {
        gestionnaire = new GestionThread(this);
        hauteur = h;
        largeur = l;
        tabCases = new Case[largeur][hauteur];
        HMCases = new HashMap<>();
        for (int i = 0; i < largeur; i++) {
            for (int j = 0; j < hauteur; j++) {
                Case maCase = new Case(this);
                HMCases.put(maCase, new Position(i, j));
                tabCases[i][j] = maCase;
            }
        }
        iteration = 0;
        intervalle = 1000;
    }

    public ArrayList<Case> getVoisins(Case maCase) {
        ArrayList<Case> liste = new ArrayList<>();
        Position position = HMCases.get(maCase);

        if (position.x - 1 >= 0 ) {
            liste.add(tabCases[position.x - 1][position.y]);
        }
        if (position.x + 1 < largeur) {
            liste.add(tabCases[position.x + 1][position.y]);
        }
        if (position.y - 1 >= 0) {
            liste.add(tabCases[position.x][position.y - 1]);
        }
        if (position.y + 1 < hauteur) {
            liste.add(tabCases[position.x][position.y + 1]);
        }
        if (position.x - 1 >= 0 && position.y+1 < hauteur){
            liste.add(tabCases[position.x-1][position.y + 1]);
        }
        if (position.x - 1 >= 0 && position.y-1 >= 0) {
            liste.add(tabCases[position.x-1][position.y - 1]);
        }
        if (position.x + 1 < largeur && position.y+1 < hauteur) {
            liste.add(tabCases[position.x+1][position.y + 1]);
        }
        if (position.x + 1 < largeur && position.y - 1 >= 0) {
            liste.add(tabCases[position.x+1][position.y - 1]);
        }
        return liste;
    }

    private void update() {
        Boolean tabResult[][] = new Boolean[largeur][hauteur];
        for (int i = 0; i < largeur; i++) {
            for (int y = 0; y < hauteur; y++) {
                tabResult[i][y] = tabCases[i][y].calculEtatSuivant();
            }
        }
        for (int i = 0; i < largeur; i++) {
            for (int y = 0; y < hauteur; y++) {
                tabCases[i][y].changerEtat();
            }
        }
        
        setChanged();
        notifyObservers(tabResult);
        iteration++;
        setChanged();
        notifyObservers(iteration);
    }

    @Override
   public void run() {
        while (true) {
            if(gestionnaire.aMettreEnPause()){
                gestionnaire.pause();
            }
            update();
            try {
                Thread.currentThread().sleep(intervalle);
            } catch (InterruptedException ex) {
                Logger.getLogger(Environnement.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }

    
    public void start() {
        gestionnaire.start();
        iteration = 0;
    }

    public void pause() {
        gestionnaire.mettreEnPause();
    }

    public void reprendre() {
       gestionnaire.reprendre();
    }
    
    public boolean isPaused()
    {
            return gestionnaire.aMettreEnPause();
    }
    
    public boolean isStarted(){
        return gestionnaire.isStarted();
    }

    public void initCases() {
        iteration = 0;
        Boolean tabResult[][] = new Boolean[largeur][hauteur];
        for (int i = 0; i < largeur; i++) {
            for (int y = 0; y < hauteur; y++) {
                tabCases[i][y].setEtatAlea();
                tabResult[i][y] = tabCases[i][y].getEtatCourant();
            }
        }
        setChanged();
        notifyObservers(tabResult);
        setChanged();
        notifyObservers(iteration);
    }
    
    public Case[][] getCases(){
        return tabCases;
    }
    
    public void setCases(boolean[][] tabVue){
        for(int i = 0; i < largeur; i++){
            for(int y = 0; y < hauteur; y++){
                if(tabVue[i][y])
                    tabCases[i][y].setEtat(true);
                else
                    tabCases[i][y].setEtat(false);
            }
        }
    }
    
    public void clearCases(){
        iteration = 0;
        Boolean[][] tabResult = new Boolean[largeur][hauteur];
        for(int i = 0; i < largeur; i++){
            for(int y = 0; y < hauteur; y++){
                tabCases[i][y].setEtat(false);
                tabResult[i][y] = false;
            }
        }
        setChanged();
        notifyObservers(tabResult);
        setChanged();
        notifyObservers(iteration);
    }
    
    public void changeIntervalle(int inter){
        intervalle = inter;
    }
    
    public void save(String nom)
    {
        try {
            FileWriter f = new FileWriter(nom);
            BufferedWriter bf = new BufferedWriter(f);
            bf.write(hauteur+"\n"+largeur+"\n");
            for(int i = 0; i < hauteur; i++){
                for(int y = 0; y<largeur; y++)
                {
                    if(tabCases[y][i].getEtatCourant())
                        bf.write("1");
                    else
                        bf.write("0");
                }
                bf.write("\n");
            }
            bf.close();
            f.close();
        } catch (IOException ex) {
            Logger.getLogger(Environnement.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
    public void open(String nom)
    {
        Boolean[][] tabResult = null;
        try {
            FileReader f = new FileReader(nom);
            BufferedReader bf = new BufferedReader(f);
            hauteur = Integer.parseInt(bf.readLine());
            largeur = Integer.parseInt(bf.readLine());
            tabResult = new Boolean[largeur][hauteur];
            
            tabCases = new Case[largeur][hauteur];
            HMCases = new HashMap<>();
            for(int i = 0; i < hauteur; i++){
                for(int y = 0; y<largeur; y++)
                {
                    Case maCase = new Case(this);
                    tabCases[y][i] = maCase;
                    HMCases.put(maCase, new Position(y, i));
                    int c = bf.read();
                    
                    if( c == '1')
                    {
                        tabCases[y][i].setEtat(true);
                        tabResult[y][i] = true;
                    }
                    else if(c == '0')
                    {
                        tabCases[y][i].setEtat(false);
                        tabResult[y][i] = false;
                    }
                        
                }
                
                bf.read();
            }
            bf.close();
            f.close();
        } catch (IOException ex) {
            Logger.getLogger(Environnement.class.getName()).log(Level.SEVERE, null, ex);
        }
        iteration = 0;
        Integer size[] = new Integer[2];
        size[0] = largeur;
        size[1] = hauteur;
        setChanged();
        notifyObservers(size);
        setChanged();
        notifyObservers(tabResult);
        setChanged();
        notifyObservers(iteration);
    }
    
    public void resize(Integer[] size)
    {
         largeur = size[0];
         hauteur = size[1];
         
         tabCases = new Case[size[0]][size[1]];
         HMCases = new HashMap<>();
         
         for(int i = 0; i < size[0]; i++){
             for(int y = 0; y < size[1]; y++){
                 Case maCase = new Case(this);
                 tabCases[i][y] = maCase;
                 HMCases.put(maCase, new Position(i, y));
             }
         }
         iteration = 0;
         setChanged();
         notifyObservers(iteration);
        
    }
    
    public void resend(){
        Boolean tabResult[][] = new Boolean[largeur][hauteur];
        for (int i = 0; i < largeur; i++) {
            for (int y = 0; y < hauteur; y++) {
                tabResult[i][y] = tabCases[i][y].getEtatCourant();
            }
        }
        setChanged();
        notifyObservers(tabResult);
    }
}
